﻿using MathNet.Numerics;
using MathNet.Numerics.IntegralTransforms;
using MathNet.Numerics.Providers.FourierTransform;
using System;
using System.Numerics;
using UtilZ.Dotnet.Ex.Model;

namespace UtilZ.Dotnet.Ex.FourierTransform
{
    /// <summary>
    /// Fourier变换类
    /// </summary>
    unsafe public partial class FourierEx
    {
        /// <summary>
        /// Sequences with length greater than Math.Sqrt(Int32.MaxValue) + 1
        /// will cause k*k in the Bluestein sequence to overflow (GH-286).
        /// </summary>
        private const int BluesteinSequenceLengthThreshold = 46341;


        /// <summary>
        /// Applies the forward Fast Fourier Transform (FFT) to arbitrary-length sample vectors.
        /// </summary>
        /// <param name="samples">Sample vector, where the FFT is evaluated in place.</param>
        /// <param name="options">Fourier Transform Convention Options.</param>
        public static void Forward(in SpanZ<Complex32> samples, FourierOptions options)
        {
            if (samples.Length > int.MaxValue)
            {
                throw new ArgumentOutOfRangeException(nameof(samples), $"数据长度不能超过{int.MaxValue}");
            }

            switch (options)
            {
                case FourierOptions.NoScaling:
                case FourierOptions.AsymmetricScaling://Matlab = AsymmetricScaling,
                    PrimitiveForward(samples, FourierTransformScaling.NoScaling);
                    break;
                //case FourierOptions.InverseExponent:
                //    FourierTransformControl.Provider.Backward(samples, FourierTransformScaling.SymmetricScaling);
                //    break;
                //case FourierOptions.InverseExponent | FourierOptions.NoScaling:
                //case FourierOptions.InverseExponent | FourierOptions.AsymmetricScaling:
                //    FourierTransformControl.Provider.Backward(samples, FourierTransformScaling.NoScaling);
                //    break;
                //default:
                //    FourierTransformControl.Provider.Forward(samples, FourierTransformScaling.SymmetricScaling);
                //    break;
                default:
                    throw new NotImplementedException();
            }
        }

        /// <summary>
        /// Applies the forward Fast Fourier Transform (FFT) to arbitrary-length sample vectors.
        /// </summary>
        /// <param name="samples">Sample vector, where the FFT is evaluated in place.</param>
        /// <param name="options">Fourier Transform Convention Options.</param>
        public static void Forward(in SpanZ<Complex> samples, FourierOptions options)
        {
            switch (options)
            {
                case FourierOptions.NoScaling:
                case FourierOptions.AsymmetricScaling:
                    PrimitiveForward(samples, FourierTransformScaling.NoScaling);
                    break;
                //case FourierOptions.InverseExponent:
                //    FourierTransformControl.Provider.Backward(samples, FourierTransformScaling.SymmetricScaling);
                //    break;
                //case FourierOptions.InverseExponent | FourierOptions.NoScaling:
                //case FourierOptions.InverseExponent | FourierOptions.AsymmetricScaling:
                //    FourierTransformControl.Provider.Backward(samples, FourierTransformScaling.NoScaling);
                //    break;
                //default:
                //    FourierTransformControl.Provider.Forward(samples, FourierTransformScaling.SymmetricScaling);
                //    break;
                default:
                    throw new NotImplementedException();
            }
        }

        /// <summary>
        /// Applies the forward Fast Fourier Transform (FFT) to arbitrary-length sample vectors.
        /// </summary>
        /// <param name="samples">Sample vector, where the FFT is evaluated in place.</param>
        /// <param name="options">Fourier Transform Convention Options.</param>
        public static void Forward(in IQSpanZ<double> samples, FourierOptions options)
        {
            switch (options)
            {
                case FourierOptions.NoScaling:
                case FourierOptions.AsymmetricScaling:
                    PrimitiveForward(samples, FourierTransformScaling.NoScaling);
                    break;
                //case FourierOptions.InverseExponent:
                //    FourierTransformControl.Provider.Backward(samples, FourierTransformScaling.SymmetricScaling);
                //    break;
                //case FourierOptions.InverseExponent | FourierOptions.NoScaling:
                //case FourierOptions.InverseExponent | FourierOptions.AsymmetricScaling:
                //    FourierTransformControl.Provider.Backward(samples, FourierTransformScaling.NoScaling);
                //    break;
                //default:
                //    FourierTransformControl.Provider.Forward(samples, FourierTransformScaling.SymmetricScaling);
                //    break;
                default:
                    throw new NotImplementedException();
            }
        }

        /// <summary>
        /// Packed Real-Complex forward Fast Fourier Transform (FFT) to arbitrary-length sample vectors.
        /// Since for real-valued time samples the complex spectrum is conjugate-even (symmetry),
        /// the spectrum can be fully reconstructed from the positive frequencies only (first half).
        /// The data array needs to be N+2 (if N is even) or N+1 (if N is odd) long in order to support such a packed spectrum.
        /// </summary>
        /// <param name="samples">Data array of length N+2 (if N is even) or N+1 (if N is odd).</param>
        /// <param name="temp">临时数据,其长度为真实数据长度(The number of samples).</param>
        /// <param name="options">Fourier Transform Convention Options.</param>
        public static void ForwardReal(in SpanZ<float> samples, SpanZ<Complex32> temp, FourierOptions options = FourierOptions.Default)
        {
            int length = temp.Length.IsEven() ? temp.Length + 2 : temp.Length + 1;
            if (samples.Length < length)
            {
                throw new ArgumentException($"The given array is too small. It must be at least {length} long.");
            }

            if ((options & FourierOptions.InverseExponent) == FourierOptions.InverseExponent)
            {
                throw new NotSupportedException();
            }

            switch (options)
            {
                case FourierOptions.NoScaling:
                case FourierOptions.AsymmetricScaling:
                    //FourierTransformControl.Provider.ForwardReal(data, n, FourierTransformScaling.NoScaling);
                    PrimitiveForwardReal(samples, temp, FourierOptions.NoScaling);
                    break;
                default:
                    //FourierTransformControl.Provider.ForwardReal(data, n, FourierTransformScaling.SymmetricScaling);
                    throw new NotImplementedException();
                    //break;
            }
        }

        /// <summary>
        /// Packed Real-Complex forward Fast Fourier Transform (FFT) to arbitrary-length sample vectors.
        /// Since for real-valued time samples the complex spectrum is conjugate-even (symmetry),
        /// the spectrum can be fully reconstructed form the positive frequencies only (first half).
        /// The data array needs to be N+2 (if N is even) or N+1 (if N is odd) long in order to support such a packed spectrum.
        /// </summary>
        /// <param name="samples">Data array of length N+2 (if N is even) or N+1 (if N is odd).</param>
        /// <param name="temp">临时数据,其长度为真实数据长度(The number of samples).</param>
        /// <param name="options">Fourier Transform Convention Options.</param>
        public static void ForwardReal(in SpanZ<double> samples, SpanZ<Complex> temp, FourierOptions options = FourierOptions.Default)
        {
            int length = temp.Length.IsEven() ? temp.Length + 2 : temp.Length + 1;
            if (samples.Length < length)
            {
                throw new ArgumentException($"The given array is too small. It must be at least {length} long.");
            }

            if ((options & FourierOptions.InverseExponent) == FourierOptions.InverseExponent)
            {
                throw new NotSupportedException();
            }

            switch (options)
            {
                case FourierOptions.NoScaling:
                case FourierOptions.AsymmetricScaling:
                    PrimitiveForwardReal(samples, temp, FourierOptions.NoScaling);
                    //FourierTransformControl.Provider.ForwardReal(data, n, FourierTransformScaling.NoScaling);
                    break;
                default:
                    //FourierTransformControl.Provider.ForwardReal(data, n, FourierTransformScaling.SymmetricScaling);
                    //break;
                    throw new NotImplementedException();
            }
        }









        /// <summary>
        /// Applies the inverse Fast Fourier Transform (iFFT) to arbitrary-length sample vectors.
        /// </summary>
        /// <param name="spectrum">Spectrum data, where the iFFT is evaluated in place.</param>
        /// <param name="options">Fourier Transform Convention Options.</param>
        public static void Inverse(in SpanZ<Complex32> spectrum, FourierOptions options)
        {
            switch (options)
            {
                //case FourierOptions.NoScaling:
                //    FourierTransformControl.Provider.Backward(spectrum, FourierTransformScaling.NoScaling);
                //    break;
                case FourierOptions.AsymmetricScaling://Matlab = AsymmetricScaling,
                    Inverse(spectrum, FourierTransformScaling.BackwardScaling);
                    break;
                //case FourierOptions.InverseExponent:
                //    FourierTransformControl.Provider.Forward(spectrum, FourierTransformScaling.SymmetricScaling);
                //    break;
                //case FourierOptions.InverseExponent | FourierOptions.NoScaling:
                //    FourierTransformControl.Provider.Forward(spectrum, FourierTransformScaling.NoScaling);
                //    break;
                //case FourierOptions.InverseExponent | FourierOptions.AsymmetricScaling:
                //    FourierTransformControl.Provider.Forward(spectrum, FourierTransformScaling.ForwardScaling);
                //    break;
                //default:
                //    FourierTransformControl.Provider.Backward(spectrum, FourierTransformScaling.SymmetricScaling);
                //    break;
                default:
                    throw new NotImplementedException();
            }
        }

        /// <summary>
        /// Applies the inverse Fast Fourier Transform (iFFT) to arbitrary-length sample vectors.
        /// </summary>
        /// <param name="spectrum">Spectrum data, where the iFFT is evaluated in place.</param>
        /// <param name="options">Fourier Transform Convention Options.</param>
        public static void Inverse(in SpanZ<Complex> spectrum, FourierOptions options)
        {
            switch (options)
            {
                //case FourierOptions.NoScaling:
                //    FourierTransformControl.Provider.Backward(spectrum, FourierTransformScaling.NoScaling);
                //    break;
                case FourierOptions.AsymmetricScaling:
                    Inverse(spectrum, FourierTransformScaling.BackwardScaling);
                    break;
                //case FourierOptions.InverseExponent:
                //    FourierTransformControl.Provider.Forward(spectrum, FourierTransformScaling.SymmetricScaling);
                //    break;
                //case FourierOptions.InverseExponent | FourierOptions.NoScaling:
                //    FourierTransformControl.Provider.Forward(spectrum, FourierTransformScaling.NoScaling);
                //    break;
                //case FourierOptions.InverseExponent | FourierOptions.AsymmetricScaling:
                //    FourierTransformControl.Provider.Forward(spectrum, FourierTransformScaling.ForwardScaling);
                //    break;
                //default:
                //    FourierTransformControl.Provider.Backward(spectrum, FourierTransformScaling.SymmetricScaling);
                //    break;
                default:
                    throw new NotImplementedException();
            }
        }

        /// <summary>
        /// Applies the inverse Fast Fourier Transform (iFFT) to arbitrary-length sample vectors.
        /// </summary>
        /// <param name="spectrum">Spectrum data, where the iFFT is evaluated in place.</param>
        /// <param name="options">Fourier Transform Convention Options.</param>
        public static void Inverse(in IQSpanZ<double> spectrum, FourierOptions options)
        {
            switch (options)
            {
                //case FourierOptions.NoScaling:
                //    FourierTransformControl.Provider.Backward(spectrum, FourierTransformScaling.NoScaling);
                //    break;
                case FourierOptions.AsymmetricScaling:
                    Inverse(spectrum, FourierTransformScaling.BackwardScaling);
                    break;
                //case FourierOptions.InverseExponent:
                //    FourierTransformControl.Provider.Forward(spectrum, FourierTransformScaling.SymmetricScaling);
                //    break;
                //case FourierOptions.InverseExponent | FourierOptions.NoScaling:
                //    FourierTransformControl.Provider.Forward(spectrum, FourierTransformScaling.NoScaling);
                //    break;
                //case FourierOptions.InverseExponent | FourierOptions.AsymmetricScaling:
                //    FourierTransformControl.Provider.Forward(spectrum, FourierTransformScaling.ForwardScaling);
                //    break;
                //default:
                //    FourierTransformControl.Provider.Backward(spectrum, FourierTransformScaling.SymmetricScaling);
                //    break;
                default:
                    throw new NotImplementedException();
            }
        }

        /// <summary>
        /// Packed Real-Complex inverse Fast Fourier Transform (iFFT) to arbitrary-length sample vectors.
        /// Since for real-valued time samples the complex spectrum is conjugate-even (symmetry),
        /// the spectrum can be fully reconstructed form the positive frequencies only (first half).
        /// The data array needs to be N+2 (if N is even) or N+1 (if N is odd) long in order to support such a packed spectrum.
        /// </summary>
        /// <param name="samples">Data array of length N+2 (if N is even) or N+1 (if N is odd).</param>
        /// <param name="temp">临时数据,其长度为真实数据长度(The number of samples).</param>
        /// <param name="options">Fourier Transform Convention Options.</param>
        public static void InverseReal(SpanZ<float> samples, SpanZ<Complex32> temp, FourierOptions options = FourierOptions.Default)
        {
            int length = temp.Length.IsEven() ? temp.Length + 2 : temp.Length + 1;
            if (samples.Length < length)
            {
                throw new ArgumentException($"The given array is too small. It must be at least {length} long.");
            }

            if ((options & FourierOptions.InverseExponent) == FourierOptions.InverseExponent)
            {
                throw new NotSupportedException();
            }

            switch (options)
            {
                //case FourierOptions.NoScaling:
                //    FourierTransformControl.Provider.BackwardReal(data, n, FourierTransformScaling.NoScaling);
                //    break;
                case FourierOptions.AsymmetricScaling:
                    //FourierTransformControl.Provider.BackwardReal(data, n, FourierTransformScaling.BackwardScaling);
                    BackwardReal(samples, temp, FourierTransformScaling.BackwardScaling);
                    break;
                default:
                    //FourierTransformControl.Provider.BackwardReal(data, n, FourierTransformScaling.SymmetricScaling);
                    //break;
                    throw new NotImplementedException();
            }
        }

        /// <summary>
        /// Packed Real-Complex inverse Fast Fourier Transform (iFFT) to arbitrary-length sample vectors.
        /// Since for real-valued time samples the complex spectrum is conjugate-even (symmetry),
        /// the spectrum can be fully reconstructed form the positive frequencies only (first half).
        /// The data array needs to be N+2 (if N is even) or N+1 (if N is odd) long in order to support such a packed spectrum.
        /// </summary>
        /// <param name="data">Data array of length N+2 (if N is even) or N+1 (if N is odd).</param>
        /// <param name="temp">临时数据,其长度为真实数据长度(The number of samples).</param>
        /// <param name="options">Fourier Transform Convention Options.</param>
        public static void InverseReal(SpanZ<double> data, SpanZ<Complex> temp, FourierOptions options = FourierOptions.Default)
        {
            int length = temp.Length.IsEven() ? temp.Length + 2 : temp.Length + 1;
            if (data.Length < length)
            {
                throw new ArgumentException($"The given array is too small. It must be at least {length} long.");
            }

            if ((options & FourierOptions.InverseExponent) == FourierOptions.InverseExponent)
            {
                throw new NotSupportedException();
            }

            switch (options)
            {
                //case FourierOptions.NoScaling:
                //    FourierTransformControl.Provider.BackwardReal(data, n, FourierTransformScaling.NoScaling);
                //    break;
                case FourierOptions.AsymmetricScaling:
                    //FourierTransformControl.Provider.BackwardReal(data, n, FourierTransformScaling.BackwardScaling);
                    BackwardReal(data, temp, FourierTransformScaling.BackwardScaling);
                    break;
                default:
                    //FourierTransformControl.Provider.BackwardReal(data, n, FourierTransformScaling.SymmetricScaling);
                    //break;
                    throw new NotImplementedException();
            }
        }


    }


}
